import asyncio
from typing import List

from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.fsm.storage.redis import DefaultKeyBuilder, RedisStorage

from app.bot import register_dialogs, register_handlers
from app.bot.middlewares.config import ConfigMiddleware
from app.bot.middlewares.database import DbSessionMiddleware
from app.bot.utils import broadcaster
from app.bot.utils.logger import configure_logging, logger
from app.bot.utils.set_commands import set_commands
from app.config import load_config
from app.database.setup import create_db_session


async def on_startup(bot: Bot, admin_ids: List[int]):
    await broadcaster.broadcast(bot, admin_ids, "Бот запущен")


def register_global_middlewares(dp: Dispatcher, config, session_factory):
    dp.message.outer_middleware(ConfigMiddleware(config))
    dp.callback_query.outer_middleware(ConfigMiddleware(config))
    dp.message.outer_middleware(DbSessionMiddleware(session_factory))
    dp.callback_query.outer_middleware(DbSessionMiddleware(session_factory))


async def main():
    configure_logging()

    logger.info("Starting bot")

    config = load_config(".env")

    if config.tg_bot.use_redis:
        storage = RedisStorage.from_url(
            url=config.redis.url,
            key_builder=DefaultKeyBuilder(with_destiny=True),
        )
    else:
        storage = MemoryStorage()

    bot = Bot(token=config.tg_bot.token, parse_mode="HTML")
    dp = Dispatcher(storage=storage)
    session_factory = await create_db_session(config)

    register_handlers(dp)
    register_dialogs(dp)

    register_global_middlewares(dp, config, session_factory)
    await set_commands(bot)

    await on_startup(bot, config.tg_bot.admin_ids)
    await dp.start_polling(bot)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except (KeyboardInterrupt, SystemExit):
        logger.error("Bot stopped!")
